// Copyright (c) MatrixFramework. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using MatrixFramework.Keycloak.Abstractions.Services;

namespace MatrixFramework.Keycloak.Services;

/// <summary>
/// 默认租户解析器
/// 支持多种租户解析策略
/// </summary>
public class DefaultTenantResolver : ITenantResolver
{
    private readonly ILogger<DefaultTenantResolver>? _logger;
    private readonly ITenantProvider[] _tenantProviders;

    public DefaultTenantResolver(IEnumerable<ITenantProvider> tenantProviders, ILogger<DefaultTenantResolver>? logger = null)
    {
        _tenantProviders = tenantProviders?.ToArray() ?? Array.Empty<ITenantProvider>();
        _logger = logger;
    }

    /// <summary>
    /// 解析当前租户
    /// </summary>
    /// <returns>租户ID，如果无法解析则返回null</returns>
    public async Task<string?> ResolveTenantAsync()
    {
        if (_tenantProviders.Length == 0)
        {
            _logger?.LogDebug("没有配置租户提供程序，返回默认租户");
            return "default";
        }

        // 按优先级尝试各个租户提供程序
        foreach (var provider in _tenantProviders)
        {
            try
            {
                var tenantId = await provider.GetTenantIdAsync();
                if (!string.IsNullOrWhiteSpace(tenantId))
                {
                    _logger?.LogDebug("租户提供程序 {ProviderType} 解析到租户: {TenantId}",
                        provider.GetType().Name, tenantId);
                    return tenantId;
                }
            }
            catch (Exception ex)
            {
                _logger?.LogWarning(ex, "租户提供程序 {ProviderType} 解析失败",
                    provider.GetType().Name);
                continue;
            }
        }

        _logger?.LogDebug("所有租户提供程序都无法解析租户，返回默认租户");
        return "default";
    }
}

/// <summary>
/// 租户提供程序接口
/// </summary>
public interface ITenantProvider
{
    /// <summary>
    /// 获取租户ID
    /// </summary>
    /// <returns>租户ID</returns>
    Task<string?> GetTenantIdAsync();
}

/// <summary>
/// HTTP头部租户提供程序
/// 从HTTP请求头中获取租户信息
/// </summary>
public class HeaderTenantProvider : ITenantProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly string _headerName;
    private readonly ILogger<HeaderTenantProvider>? _logger;

    public HeaderTenantProvider(
        IHttpContextAccessor httpContextAccessor,
        string headerName = "X-Tenant-ID",
        ILogger<HeaderTenantProvider>? logger = null)
    {
        _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
        _headerName = headerName;
        _logger = logger;
    }

    public Task<string?> GetTenantIdAsync()
    {
        var context = _httpContextAccessor.HttpContext;
        if (context?.Request?.Headers == null)
        {
            _logger?.LogDebug("HTTP上下文为空，无法从头部获取租户信息");
            return Task.FromResult<string?>(null);
        }

        if (context.Request.Headers.TryGetValue(_headerName, out var tenantId))
        {
            var tenantIdValue = tenantId.ToString();
            if (!string.IsNullOrWhiteSpace(tenantIdValue))
            {
                _logger?.LogDebug("从HTTP头部 {HeaderName} 获取到租户: {TenantId}",
                    _headerName, tenantIdValue);
                return Task.FromResult<string?>(tenantIdValue);
            }
        }

        _logger?.LogDebug("HTTP头部 {HeaderName} 中未找到租户信息", _headerName);
        return Task.FromResult<string?>(null);
    }
}

/// <summary>
/// 查询参数租户提供程序
/// 从URL查询参数中获取租户信息
/// </summary>
public class QueryTenantProvider : ITenantProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly string _parameterName;
    private readonly ILogger<QueryTenantProvider>? _logger;

    public QueryTenantProvider(
        IHttpContextAccessor httpContextAccessor,
        string parameterName = "tenant",
        ILogger<QueryTenantProvider>? logger = null)
    {
        _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
        _parameterName = parameterName;
        _logger = logger;
    }

    public Task<string?> GetTenantIdAsync()
    {
        var context = _httpContextAccessor.HttpContext;
        if (context?.Request?.Query == null)
        {
            _logger?.LogDebug("HTTP上下文为空，无法从查询参数获取租户信息");
            return Task.FromResult<string?>(null);
        }

        if (context.Request.Query.TryGetValue(_parameterName, out var tenantId))
        {
            var tenantIdValue = tenantId.ToString();
            if (!string.IsNullOrWhiteSpace(tenantIdValue))
            {
                _logger?.LogDebug("从查询参数 {ParameterName} 获取到租户: {TenantId}",
                    _parameterName, tenantIdValue);
                return Task.FromResult<string?>(tenantIdValue);
            }
        }

        _logger?.LogDebug("查询参数 {ParameterName} 中未找到租户信息", _parameterName);
        return Task.FromResult<string?>(null);
    }
}

/// <summary>
/// 子域名租户提供程序
/// 从域名子部分获取租户信息
/// </summary>
public class SubdomainTenantProvider : ITenantProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly string[] _excludeSubdomains;
    private readonly ILogger<SubdomainTenantProvider>? _logger;

    public SubdomainTenantProvider(
        IHttpContextAccessor httpContextAccessor,
        string[]? excludeSubdomains = null,
        ILogger<SubdomainTenantProvider>? logger = null)
    {
        _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
        _excludeSubdomains = excludeSubdomains ?? new[] { "www", "api", "admin", "app" };
        _logger = logger;
    }

    public Task<string?> GetTenantIdAsync()
    {
        var context = _httpContextAccessor.HttpContext;
        if (context?.Request == null)
        {
            _logger?.LogDebug("HTTP上下文为空，无法从子域名获取租户信息");
            return Task.FromResult<string?>(null);
        }

              // 尝试从Host头部获取主机名
        var hostHeader = context.Request.Headers["Host"].ToString();
        if (string.IsNullOrWhiteSpace(hostHeader))
        {
            _logger?.LogDebug("主机名为空，无法从子域名获取租户信息");
            return Task.FromResult<string?>(null);
        }

        var parts = hostHeader.Split('.');
        if (parts.Length <= 2)
        {
            _logger?.LogDebug("域名 {Host} 没有子域名部分", hostHeader);
            return Task.FromResult<string?>(null);
        }

        var subdomain = parts[0].ToLowerInvariant();
        if (System.Linq.Enumerable.Contains<string>(_excludeSubdomains, subdomain))
        {
            _logger?.LogDebug("子域名 {Subdomain} 在排除列表中", subdomain);
            return Task.FromResult<string?>(null);
        }

        _logger?.LogDebug("从域名 {Host} 解析出租户子域名: {Subdomain}", hostHeader, subdomain);
        return Task.FromResult<string?>(subdomain);
    }
}

/// <summary>
/// 配置租户提供程序
/// 从配置文件中获取默认租户信息
/// </summary>
public class ConfigurationTenantProvider : ITenantProvider
{
    private readonly string _defaultTenantId;
    private readonly ILogger<ConfigurationTenantProvider>? _logger;

    public ConfigurationTenantProvider(
        string defaultTenantId = "default",
        ILogger<ConfigurationTenantProvider>? logger = null)
    {
        _defaultTenantId = defaultTenantId;
        _logger = logger;
    }

    public Task<string?> GetTenantIdAsync()
    {
        if (string.IsNullOrWhiteSpace(_defaultTenantId))
        {
            _logger?.LogDebug("配置的默认租户ID为空");
            return Task.FromResult<string?>(null);
        }

        _logger?.LogDebug("从配置获取默认租户: {TenantId}", _defaultTenantId);
        return Task.FromResult<string?>(_defaultTenantId);
    }
}